#include<iostream>

#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<unistd.h>
#include<sys/fcntl.h>
using namespace std;

#define INF 0
#define DBG 1
#define ERR 2
#define LOG_LEVEL DBG
#define LOG(level, format, ...)                                                                               \
    do                                                                                                        \
    {                                                                                                         \
        if (level < LOG_LEVEL)                                                                                \
            break;                                                                                            \
        time_t t = time(nullptr);                                                                             \
        struct tm *ltm = localtime(&t);                                                                       \
        char tmp[32] = {0};                                                                                   \
        strftime(tmp, 31, "%H:%M:%S", ltm);                                                                   \
        printf("[%p %s %s:%d] " format "\n", (void *)pthread_self(), tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
    } while (0)

#define INF_LOG(format, ...) LOG(INF, format, ##__VA_ARGS__);
#define DBG_LOG(format, ...) LOG(DBG, format, ##__VA_ARGS__);
#define ERR_LOG(format, ...) LOG(ERR, format, ##__VA_ARGS__);

#define DEFAULT_BACKLOG_SIZE 1024

class Socket
{
private:
    int sockfd_;

public:
    Socket() : sockfd_(-1)
    {
    }
    Socket(int newfd) : sockfd_(newfd)
    {
    }
    ~Socket()
    {
        Close();
    }

    // 获取fd
    int GetFd()
    {
        return sockfd_;
    }

    // 关闭套接字
    void Close()
    {
        if (sockfd_ != -1)
        {
            close(sockfd_);
            sockfd_ = -1;
        }
    }

    // 创建套接字
    bool Create()
    {
        int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sockfd < 0)
        {
            ERR_LOG("CREATE SOCKET FAILED!!");
            return false;
        }
        sockfd_ = sockfd;

        return true;
    }

    // 绑定套接字
    bool Bind(const std::string &ip, const uint16_t &port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip.c_str());

        socklen_t len = sizeof(addr);
        int n = bind(sockfd_, (struct sockaddr *)&addr, len);
        if (n < 0)
        {
            ERR_LOG("SOCKET BIND FAILED!!");
            return false;
        }

        return true;
    }

    // 监听套接字
    bool Listen(int backlog = DEFAULT_BACKLOG_SIZE)
    {
        int n = listen(sockfd_, backlog);
        if (n < 0)
        {
            ERR_LOG("SOCKET LISTEN FAILED!!");
            return false;
        }

        return true;
    }

    // 连接服务器
    bool Connect(const std::string &ip, const uint16_t &port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = port;
        addr.sin_addr.s_addr = inet_addr(ip.c_str());

        socklen_t len = sizeof(addr);
        int n = connect(sockfd_, (struct sockaddr *)&addr, len);
        if (n < 0)
        {
            ERR_LOG("SOCKET CONNECT FAILED!!");
            return false;
        }
        return true;
    }

    // 获取新连接
    int Accept()
    {
        // 后两个参数用来接收客户端的协议地址与长度，我们这里用不上
        int newfd = accept(sockfd_, nullptr, nullptr);
        if (newfd < 0)
        {
            ERR_LOG("SOCKET ACCEPT FAILED!!");
            return -1;
        }
        return newfd;
    }

    // 0表示阻塞
    ssize_t Send(const void *buf, size_t len, int flag = 0)
    {
        ssize_t n = send(sockfd_, buf, len, flag);
        if (n < 0)
        {
            // 前一错误只有设置为非阻塞才会产生
            if (errno == EAGAIN || errno == EINTR)
            {
                return 0;
            }
            else
            {
                ERR_LOG("SOCKET SEND FAILED!!");
                return -1;
            }
        }
        return n;
    }

    // 非阻塞发送
    ssize_t SendNoneBlock(const void *buf, size_t len, int flag = 0)
    {
        return Send(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT非阻塞态
    }

    // 0表示阻塞
    ssize_t Recv(void *buf, size_t len, int flag = 0)
    {
        ssize_t n = recv(sockfd_, buf, len, flag);
        if (n <= 0)
        {
            // EAGAIN 当前socket的接收缓冲区中没有数据了，在⾮阻塞的情况下才会有这个错误
            // EINTR 表⽰当前socket的阻塞等待，被信号打断了，
            if (errno == EAGAIN || errno == EINTR)
            {
                return 0;
            }
            else
            {
                ERR_LOG("SOCKET RECV FAILED!!");
                return -1;
            }
        }

        return n;
    }
    // 非阻塞读取
    ssize_t RecvNoneBlock(void *buf, size_t len, int flag = 0)
    {
        return Recv(buf, len, MSG_DONTWAIT);
    }

    // 开启地址端口复用
    void ReuseAddress()
    {
        // int setsockopt(int fd, int leve, int optname, void *val, int vallen)
        int val = 1;
        int n = setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &val, sizeof(val));
        if (n < 0)
        {
            ERR_LOG("SOCKET SETOPT FAILED!!");
        }
    }
    // 开启非阻塞
    void SetNonBlock()
    {
        // int fcntl(int fd, int cmd, ... /* arg */ )
        int fl = fcntl(sockfd_, F_GETFL);
        int n = fcntl(sockfd_, F_SETFL, fl | O_NONBLOCK);
        if (n < 0)
        {
            ERR_LOG("SOCKET SETNONBLOCK FAILED!!");
        }
    }

    // 构造一个tcp服务器
     // 如果server端操作系统内有多个网卡（每个网卡上有不同的IP地址）\
    可以要在调用bind()的时候，告诉操作系统：“我需要在 yyyy 端口上侦听，所有发送到服务器的这个端口，不管是哪个网卡/哪个IP地址接收到的数据，都是我处理的。”这时候，服务器程序则在0.0.0.0这个地址上进行侦听

    bool CreateServer(const uint16_t &port, const std::string &ip = "0.0.0.0", bool set_non_block = false)
    {
        if (Create() == false)
            return false;
        if (set_non_block)
            SetNonBlock();

        // 地址复用必须在bind前告知系统
        ReuseAddress();
        if (Bind(ip, port) == false)
            return false;
        if (Listen() == false)
            return false;

        //DBG_LOG("SERVER CREATE SUCCESS!!");
        return true;
    }

    // 构造一个tcp客户端连接
    bool CreateClient(const uint16_t &port, const std::string &ip)
    {
        if (Create() == false)
            return false;
        if (Connect(ip, port) == false)
            return false;

        DBG_LOG("CLIENT CREATE SUCCESS!!");
        return true;
    }
};


int main()
{
    Socket listen_sock;
    listen_sock.CreateServer(8888);
    while(1)
    {
        int newfd = listen_sock.Accept();

        for(;;)
        {}
    }
    return 0;
}